\section{Apéndice: Código}
\subsection{Gramatica}
\begin{verbatim}
grammar GramAntlr; 

options {
    output=AST; 
    ASTLabelType=CommonTree;
    }
 
tokens{
  INDICE;
  CONCAT;
  PARENTESIS;
  VACIO;
}

@header{
  package com.tleng; 
}

@lexer::header{
  package com.tleng;
}

x : e EOF!; 

e: a ('/'^ e)?;

a: b1=b(a1=a)?  -> {a1 != null}? ^(CONCAT $b1 $a1)
                -> b;

b: c1=c('^'c2=c)?('_'c3=c)? -> {c2 != null && c3 != null}? ^(INDICE $c1 $c2 $c3)
                            -> {c2 == null && c3 == null}? c
                            -> {c2 == null}? ^(INDICE $c1 VACIO $c3)
                            -> ^(INDICE $c1 $c2 VACIO); 

c: N | 
  '('e')' -> ^(PARENTESIS e) | 
  '{' e '}' -> e;

z : N EOF;

N :'0'..'9' | 'a'..'z' | 'A'..'Z' | '+' | '-' | '*';

ESP  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;};
\end{verbatim}

\subsection{Nuestro Tree Adaptor}

\begin{verbatim}
package com.tleng;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTreeAdaptor;

import com.tleng.Nodos.NodoConcatenacion;
import com.tleng.Nodos.NodoDivision;
import com.tleng.Nodos.NodoParentesis;
import com.tleng.Nodos.NodoSubSuperIndice;
import com.tleng.Nodos.NodoTerminal;
import com.tleng.Nodos.NodoVacio;


public class NuestroTreeAdaptor extends CommonTreeAdaptor {

	 public Object create(Token token) 
	 {
		if(token == null) 
			return super.create(token);
		
		String tipo = token.getText();

		if(tipo.contains("/"))
			return new NodoDivision(token);
		else if(tipo.contains("INDICE"))
			return new NodoSubSuperIndice(token);
		else if(tipo.contains("PARENTESIS"))
			return new NodoParentesis(token);
		else if(tipo.contains("CONCAT"))
			return new NodoConcatenacion(token);
		else if(tipo.contains("VACIO"))
			return new NodoVacio(token);
		else 
			return new NodoTerminal(token);
	}

}
\end{verbatim}

\subsection{Nodos}
\subsubsection{Concatenacion}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;


public class NodoConcatenacion extends NodoGenerico {
	
	
	public NodoConcatenacion(Token t) 
	{
		super(t);
	}
	
    public NodoConcatenacion(CommonTree node)
    { 
    	super(node); 
    }
    
    private NodoGenerico E1()    { return this;    }
    private NodoGenerico E2()    { return (NodoGenerico)this.getChild(0);    }
    private NodoGenerico E3()    { return (NodoGenerico)this.getChild(1);    }
    
    public String Imprimir()
    {
    	return E2().Imprimir() + E3().Imprimir();
    }
    
/**
    Caso E1 = E2 E3 (concatenación)
    -------------------------------

    E2.x <- E1.x
    E2.y <- E1.y
    E2.escala <- E1.escala

    E3.x <- E1.x + E2.x + separacion_concatenacion(*) 
    E3.y <- E1.y
    E3.escala <- E1.escala

    E1.ancho <- E2.ancho + E3.ancho + separacion_concatenacion(*)
    E1.alto_superior <- maximo ( E2.alto_superior, E3.alto_superior )
    E1.alto_inferior <- maximo ( E2.alto_inferior, E3.alto_inferior ) 
   **/
    
    
    public void calcularX()
    {
    	E2().x = E1().x;
    	E3().x = E1().x + E2().ancho + this.separacion_concatenacion;

    	E2().calcularX();
    	E3().calcularX();
    }
    
    public void calcularY()
    {
    	E2().y = E1().y;
    	E3().y = E1().y;
    	
    	E2().calcularY();
    	E3().calcularY();
    }
    
    public void calcularEscala()
    {
    	E2().escala = E1().escala;
    	E3().escala = E1().escala;
    	
    	E2().calcularEscala();
    	E3().calcularEscala();
    }
    
    public void calcularAncho()
    {
    	E2().calcularAncho();
    	E3().calcularAncho();
    	E1().ancho = E2().ancho + E3().ancho + this.separacion_concatenacion;
    }
    
    public void calcularAlto()
    {
    	E2().calcularAlto();
    	E3().calcularAlto();
    	E1().alto_inferior = Math.max(E2().alto_inferior, E3().alto_inferior); 
    	E1().alto_superior = Math.max(E2().alto_superior, E3().alto_superior);
    }
	
}
\end{verbatim}
\subsubsection{Division}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;

public class NodoDivision extends NodoGenerico {

	double alto_subir = 0.27;
	public NodoDivision(Token t) 
	{
		super(t);
	}
	
    public NodoDivision(CommonTree node)
    { 
    	super(node); 
    }
    
    public String Imprimir()
    {
    	return E2().Imprimir() + E3().Imprimir() + ImprimirBarraDeDivision();
    }
    
    private String ImprimirBarraDeDivision()
    {
    	return "gsave " + this.x + " " + this.y + " moveto " + this.ancho + " " + 0.0 +" rlineto stroke grestore\n";
    }
    
    private NodoGenerico E1() { return this; }
    private NodoGenerico E2() { return (NodoGenerico)this.getChild(0); }
    private NodoGenerico E3() { return (NodoGenerico)this.getChild(1); }
    
/**
    Caso E1 = E2 / E3 ( division ) 
    ------------------------------

    En este caso se sule poner la linea de division un poco por arriba de la linea de base,
    a la altura aproximada de la linea del horizontal del más ( + ) (0.28)

    E2().x = (E2().ancho > E3().ancho) ? E1().x : E1().x + E3().ancho/2 - E2().ancho/2
    E2().y = E1().y + 0.28 + separacion_division(*) + E2().altura_inferior
    E2().escala = E1().escala * escala_division(*)

    E3().x = (E3().ancho > E2().ancho) ? E1().x : E1().x + E2().ancho/2 - E3().ancho/2
    E3().y = E1().y + 0.28 - separacion_division(*) - E3().altura_superior
    E3().escala = E1().escala * escala_division(*)

    E1().ancho = maximo (E2().ancho, E3().ancho)
    E1().alto_superior = 0.28 + escala_division(*) + E2().alto_inferior + E2().alto_superior
    E1().alto_inferior = escala_division(*) - 0.28 + E3().alto_inferior + E3().alto_superior
    
**/   
    
    public void calcularX()
    {
    	E2().x = (E2().ancho > E3().ancho) ? E1().x : E1().x + E3().ancho/2 - E2().ancho/2;
    	E3().x = (E3().ancho > E2().ancho) ? E1().x : E1().x + E2().ancho/2 - E3().ancho/2;
    	
    	E2().calcularX();
    	E3().calcularX();
    }
    
    public void calcularY()
    {
    	E1().y += alto_subir * this.escala;
    	E2().y = E1().y + E2().alto_inferior + separacion_division * escala;
    	E3().y = E1().y - E3().alto_superior + separacion_division * escala;

    	E2().calcularY();
    	E3().calcularY();
    }
    
    public void calcularEscala()
    {
    	E2().escala = E1().escala * escala_division;
    	E3().escala = E1().escala * escala_division;

    	E2().calcularEscala();
    	E3().calcularEscala();
    }
    
    public void calcularAncho()
    {
    	E2().calcularAncho();
    	E3().calcularAncho();
    	E1().ancho = Math.max(E2().ancho, E3().ancho);
    }
    
    public void calcularAlto()
    {
    	E2().calcularAlto();
    	E3().calcularAlto();
    	E1().alto_inferior = E3().alto_inferior + E3().alto_superior - alto_subir * this.escala;
    	E1().alto_superior = E2().alto_inferior + E2().alto_superior + separacion_division * escala + alto_subir * this.escala;
    }
    
}
\end{verbatim}
\subsubsection{Generico}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;


public class NodoGenerico extends CommonTree {

	protected Token token;
	
	protected double x;
	protected double y;
	protected double escala;	
	protected double ancho;	
	protected double alto_inferior;	
	protected double alto_superior;	
	
	
	protected double separacion_concatenacion = 0;// es la separacion dada entre la concatenacion puede ser 0 pero podriamso poner algo mayor que esto.
	protected double separacion_division = 0.1;// Para que el texto quede un poco por arriba y por abajo de la linea (puede ser 0 o mas)
	protected double escala_division = 0.9;// Se puede achicar un poco cada parte de la division por ejemplo un 90% o se puede dejar en la misma escala.
	protected double escala_subper_subindice = 0.7;// en general 0.7
	protected double separacion_super_subindice = 0.7;// a que porcentaje de la letra general esta (70, 80%) 0.7, 0.8
	protected double ancho_parentesis = 1;// No se como es esto en.
	
	public Boolean EsVacio() { return false; }
    public NodoGenerico(Token t) 
    { 
    	super(t);
    	token=t;
    }                 // for 'int'<V>
    public NodoGenerico(CommonTree node) { super(node); }             // for dupNode
    public Tree dupNode() { return new NodoGenerico(this); } // for dup'ing type
    public String toString() { return token.getText()+"<V>";}
    
    public String Imprimir()
    {
    	return "";
    }
    
    public void SetearParametrosIniciales(double x, double y, double escala)
    {
    	this.x = x;
    	this.y = y;
    	this.escala = escala;
    }
    
    public double altoTotal() { return this.alto_inferior + this.alto_superior; }
    
    public void calcularX()
    {
    	
    }
    
    public void calcularY()
    {
    	
    }
    
    public void calcularEscala()
    {
    	
    }
    
    public void calcularAncho()
    {
    	
    }
    
    public void calcularAlto()
    {
    	
    }
}
\end{verbatim}
\subsubsection{Parentesis}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;


public class NodoParentesis extends NodoGenerico {

	public NodoParentesis(Token t) 
	{
		super(t);
	}
	
    public NodoParentesis(CommonTree node)
    { 
    	super(node); 
    }
    
    private NodoGenerico E1() { return this; }
    private NodoGenerico E2() { return (NodoGenerico)this.getChild(0); }
    
    public String Imprimir()
    {
    	return ImprimirParentesisAbre() + E2().Imprimir() + ImprimirParentesisCierra();
    }
    
    private String ImprimirParentesisAbre()
    {
    	return "gsave " + this.x + " " + (this.y - this.alto_inferior) + " moveto " + ancho_parentesis + " " + (this.altoTotal() + this.alto_inferior) + " scale (\\() show grestore\n";
    }

    private String ImprimirParentesisCierra()
    {
    	return "gsave " + (this.x+this.ancho-ancho_parentesis/2) + " " + (this.y - this.alto_inferior) + " moveto " + ancho_parentesis + " " + (this.altoTotal() + this.alto_inferior) + " scale (\\)) show grestore\n";
    }
    
    /**
     Caso E1 = (E2) ( parentesis )
	-----------------------------
	
	E2().x = E1().x + ancho_parentesis
	E2().y = E1().y
	E2().escala = E1().escala
	
	E1().ancho = E2().ancho + 2*ancho_parentesis
	E1().alto_superior = E2().alto_superior
	E1().alto_inferior = E2().alto_inferior
     */
    
    public void calcularX()
    {
    	E2().x = E1().x + ancho_parentesis/2;
    	E2().calcularX();
    }
    
    public void calcularY()
    {
    	E2().y = E1().y;
    	
    	E2().calcularY();
    }
    
    public void calcularEscala()
    {
    	E2().escala = E1().escala;
    	
    	E2().calcularEscala();
    }
    
    public void calcularAncho()
    {
    	E2().calcularAncho();
    	E1().ancho = E2().ancho + ancho_parentesis;
    }
    
    public void calcularAlto()
    {
    	E2().calcularAlto();
    	E1().alto_superior = E2().alto_superior;
    	E1().alto_inferior = E2().alto_inferior;
    }
}
\end{verbatim}
\subsubsection{SubSuperIndice}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;


public class NodoSubSuperIndice extends NodoGenerico {

	public NodoSubSuperIndice(Token t) 
	{
		super(t);
	}
	
    public NodoSubSuperIndice(CommonTree node)
    { 
    	super(node); 
    }
    
    public String Imprimir()
    {
    	String e3 = (!E3().EsVacio())? E3().Imprimir() : "";
    	String e4 = (!E4().EsVacio())? E4().Imprimir() : "";
    	
    	return E2().Imprimir() + e3 + e4;
    }
    
    private NodoGenerico E1() { return this; }
    private NodoGenerico E2() { return (NodoGenerico)this.getChild(0); }
    private NodoGenerico E3() { return (NodoGenerico)this.getChild(1); }
    private NodoGenerico E4() { return (NodoGenerico)this.getChild(2); }
    
    /***
    Caso E1 = E2^E3_E4 ( super y subindicie )
    -----------------------------------------

    En este caso tomaremos como superindice a E3 y subindice a E4 y estos 
    pueden estar o no estar para cubrir los 4 casos de la gramatica.

    E2().x = E1().x
    E2().y = E1().y
    E2().escala = E1().escala

    E3().x = E1().x + E2().ancho
    E3().y = E1().y + E2().alto_superior * separacion_super_subindice
    E3().escala = E1().escala * escala_subper_subindice

    E4().x = E1().x + E2().ancho
    E4().y = E1().y - E3().alto * (1 - separacion_super_subindice)
    E4().escala = E1().escala * escala_subper_subindice

    E1().ancho = E2().ancho + Math.max ( E3().ancho, E4().ancho )
    E1().alto_superior = E2().alto_superior * separacion_super_subindice + Math.max ( E3().alto_superior , E2().alto_superior * (1 - separacion_super_subindice)
    E1().alto_inferior = Math.max ( E4().alto_inferior + E4().alto_superior * separacion_super_subindice, E1().alto_inferior)
    
    */
    
    public void calcularX()
    {
    	E2().x = E1().x;
    	if(!E3().EsVacio())
    		E3().x = E1().x + E2().ancho;
    	if(!E4().EsVacio())
    		E4().x = E1().x + E2().ancho;
    	
    	E2().calcularX();
		E3().calcularX();
		E4().calcularX();
    }
    
    public void calcularY()
    {
    	E2().y = E1().y;
		E3().y = E1().y + E2().alto_superior * separacion_super_subindice;
		E4().y = E1().y - E4().altoTotal() * (1 - separacion_super_subindice); // TODO : Aca decia E3.alto 
    	
    	E2().calcularY();
		E3().calcularY();
		E4().calcularY();
    	
    }
    
    public void calcularEscala()
    {
    	E2().escala = E1().escala;
		E3().escala = E1().escala * escala_subper_subindice;
		E4().escala = E1().escala * escala_subper_subindice;
    	
    	E2().calcularEscala();
		E3().calcularEscala();
		E4().calcularEscala();
    	
    }
    
    public void calcularAncho()
    {
    	E2().calcularAncho();
		E3().calcularAncho();
		E4().calcularAncho();
    	
    	double maximo = (!E3().EsVacio() && !E4().EsVacio())
    						? Math.max ( E3().ancho, E4().ancho )
    						: (!E3().EsVacio()) 
    							? E3().ancho
    							: E4().ancho;
    	E1().ancho = E2().ancho + maximo;
    }
    
    public void calcularAlto()
    {
    	E2().calcularAlto();
		E3().calcularAlto();
		E4().calcularAlto();
    	
    	double maximo1 = (!E3().EsVacio())
    						? Math.max ( E3().alto_superior , E2().alto_superior * (1 - separacion_super_subindice))
    						:  E2().alto_superior * (1 - separacion_super_subindice);
    	double maximo2 = (!E4().EsVacio())
    						? Math.max ( E4().alto_inferior + E4().alto_superior * separacion_super_subindice, E1().alto_inferior)
    						: E1().alto_inferior;

    	E1().alto_superior = E2().alto_superior * separacion_super_subindice + maximo1;
    	E1().alto_inferior = maximo2;
    }
}
\end{verbatim}
\subsubsection{Terminal}
\begin{verbatim}
package com.tleng.Nodos;

import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;

public class NodoTerminal extends NodoGenerico {

	public NodoTerminal(Token t) 
	{
		super(t);
	}
	
    public NodoTerminal(CommonTree node)
    { 
    	super(node); 
    }
    
    public String Imprimir()
    {
    	double alto = alto_superior + alto_inferior;
    	return "gsave " + x + " " + y + " moveto " + ancho + " " + alto + " scale (" +  this.token.getText() + ") show grestore\n";
    }
    
    /***
    Caso E1 = l ( terminal )
	------------------------
	
	l.x <- E1.x
	l.y <- E1.y
	l.escala <- E1.escala
	
	E1.ancho <- 0.6 * E1.escala
	E1.alto_superior <- 1 * E1.escala
	E1.alto_inferior <- 0
     */
    
    public void calcularAncho()
    {
    	this.ancho = 0.6 * this.escala;
    }
    
    public void calcularAlto()
    {
    	this.alto_inferior = 0;
    	this.alto_superior = 1 * this.escala;
    }
}
\end{verbatim}
\section{Main}
\begin{verbatim}
package com.tleng;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;

import com.tleng.GramAntlrParser.x_return;
import com.tleng.Nodos.NodoGenerico;



public class Test {
	public static void main(String[] args) throws IOException, RecognitionException{
		ANTLRInputStream input = new ANTLRInputStream(System.in);

        GramAntlrLexer lexer = new GramAntlrLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        GramAntlrParser parser = new GramAntlrParser(tokens);
        parser.setTreeAdaptor(new NuestroTreeAdaptor());
        
        x_return x = parser.x();

        NodoGenerico t = (NodoGenerico)x.getTree();
        
        t.SetearParametrosIniciales(0, 0, 1);
        t.calcularEscala();
        t.calcularAncho();
        t.calcularAlto();
        t.calcularX();
        t.calcularY();
        
        String res = t.Imprimir();
        
        String nombre = "";
        if(args.length != 0){
        	nombre = args[0];
        }else{
        	nombre = "res.ps";
        }
        FileWriter fstream = new FileWriter(nombre);
        BufferedWriter out = new BufferedWriter(fstream);
        
        out.write("%!PS-Adobe-3.0 EPSF-3.0\n");
        out.write("30 200 translate\n");
        out.write("50 50 scale\n");
        out.write(".03 setlinewidth\n");
        out.write("/Courier findfont setfont\n");
        out.write(res);
        out.write("showpage\n");
        out.close();

	}
}
\end{verbatim}
